package com.whfc.emp.service.impl;

import com.whfc.common.enums.LocaleState;
import com.whfc.common.exception.BizException;
import com.whfc.common.util.CollectionUtil;
import com.whfc.common.util.DateUtil;
import com.whfc.common.util.MathUtil;
import com.whfc.emp.dao.*;
import com.whfc.emp.dto.*;
import com.whfc.emp.dto.train.AppBoardEmpGroupCountDTO;
import com.whfc.emp.enums.*;
import com.whfc.emp.manager.CommonEmpConfigManager;
import com.whfc.emp.param.EmpAttendPlan;
import com.whfc.emp.service.AppEmpBoardService;
import com.whfc.entity.dto.KeyAndSizeDTO;
import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @ClasssName AppEmpBoardServiceImpl
 * @Description 大屏服务
 * @Author hw
 * @Date 2021/1/7 19:19
 * @Version 1.0
 */
@DubboService(interfaceClass = AppEmpBoardService.class, version = "1.0.0", timeout = 30 * 1000)
public class AppEmpBoardServiceImpl implements AppEmpBoardService {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private AppEmpMapper appEmpMapper;

    @Autowired
    private AppEmpEnterRecordMapper appEmpEnterRecordMapper;

    @Autowired
    private CommonEmpConfigManager commonEmpConfigManager;

    @Autowired
    private AppEmpAttendRecordMapper appEmpAttendRecordMapper;

    @Autowired
    private AppEmpWarnMapper appEmpWarnMapper;

    @Autowired
    private AppEmpDataMapper appEmpDataMapper;

    @Autowired
    private AppEmpDayMapper appEmpDayMapper;

    @Autowired
    private AppEmpGroupMapper appEmpGroupMapper;

    @Autowired
    private AppFaceGateRecordMapper appFaceGateRecordMapper;

    @Autowired
    private AppEmpDeptDayMapper appEmpDeptDayMapper;

    @Override
    public AppBoardEmpOverviewDTO getEmpData(Integer deptId) throws BizException {
        logger.info("大屏-人员,deptId:{}", deptId);
        AppBoardEmpOverviewDTO data = new AppBoardEmpOverviewDTO();
        // 查找用户及其子组织结构
        List<AppEmpDTO> appEmpList = appEmpMapper.selectAnaEmpByDeptId(deptId);

        // 在岗人员统计
        int managerNum = 0;
        int workerNum = 0;
        int managerAttendNum = 0;
        int workerAttendNum = 0;
        int managerLocalNum = 0;
        int workerLocalNum = 0;
        // 在岗工种
        Set<AppWorkTypeDTO> workTypeSet = new HashSet<>();
        for (AppEmpDTO appEmpDTO : appEmpList) {
            AppWorkTypeDTO appWorkTypeDTO = new AppWorkTypeDTO();
            appWorkTypeDTO.setWorkTypeId(appEmpDTO.getWorkTypeId());
            appWorkTypeDTO.setWorkTypeName(appEmpDTO.getWorkTypeName());
            appWorkTypeDTO.setWorkRoleId(appEmpDTO.getWorkRoleId());
            workTypeSet.add(appWorkTypeDTO);

            Integer attendState = appEmpDTO.getAttendState();
            Integer localeState = appEmpDTO.getLocaleState();

            if (AppWorkRole.MANAGER.value().equals(appEmpDTO.getWorkRoleId())) {
                managerNum++;
                if (AttendState.ATTEND.getValue().equals(attendState)) {
                    managerAttendNum++;
                    if (LocaleState.IN.getValue().equals(localeState)) {
                        managerLocalNum++;
                    }
                }
            } else {
                workerNum++;
                if (AttendState.ATTEND.getValue().equals(attendState)) {
                    workerAttendNum++;
                    if (LocaleState.IN.getValue().equals(localeState)) {
                        workerLocalNum++;
                    }
                }
            }
        }
        AppBoardEmpNumDTO appBoardEmpNumDTO = new AppBoardEmpNumDTO();
        appBoardEmpNumDTO.setManagerNum(managerNum);
        appBoardEmpNumDTO.setManagerAttendNum(managerAttendNum);
        appBoardEmpNumDTO.setManagerLocaleNum(managerLocalNum);
        appBoardEmpNumDTO.setWorkerNum(workerNum);
        appBoardEmpNumDTO.setWorkerAttendNum(workerAttendNum);
        appBoardEmpNumDTO.setWorkerLocaleNum(workerLocalNum);
        appBoardEmpNumDTO.setNum(workerNum + managerNum);

        List<AppEmpAnaNumDTO> workTypeEmpList = new ArrayList<>();
        List<AppEmpAnaNumDTO> attendStateEmpList = new ArrayList<>();
        for (AppWorkTypeDTO workType : workTypeSet) {
            Integer workTypeId = workType.getWorkTypeId();
            String workTypeName = workType.getWorkTypeName();
            Integer workRoleId = workType.getWorkRoleId();
            Integer localeNum = 0;
            Integer offLocaleNum = 0;
            Integer absenceNum = 0;
            Integer num = 0;

            for (AppEmpDTO appEmpDTO : appEmpList) {
                Integer localeState = appEmpDTO.getLocaleState();
                Integer attendState = appEmpDTO.getAttendState();
                Integer workTypeId1 = appEmpDTO.getWorkTypeId();
                Integer workRoleId1 = appEmpDTO.getWorkRoleId();
                if (workRoleId != null && workRoleId.equals(workRoleId1) && workTypeId.equals(workTypeId1)) {
                    num++;

                    if (AttendState.ABSENCE.getValue().equals(attendState)) {
                        absenceNum++;
                    }
                    if (AttendState.ATTEND.getValue().equals(attendState) && LocaleState.IN.getValue().equals(localeState)) {
                        localeNum++;
                    }
                    if (AttendState.ATTEND.getValue().equals(attendState) && LocaleState.OUT.getValue().equals(localeState)) {
                        offLocaleNum++;
                    }
                }
            }
            if (workTypeId != null) {
                // 在岗工种统计
                AppEmpAnaNumDTO workTypeAnaNumDTO = new AppEmpAnaNumDTO();
                workTypeAnaNumDTO.setNum(num);
                workTypeAnaNumDTO.setName(workTypeName);
                workTypeAnaNumDTO.setWorkRoleId(workRoleId);
                workTypeAnaNumDTO.setId(workTypeId);
                workTypeEmpList.add(workTypeAnaNumDTO);
            }
            // 今日出勤状态
            AppEmpAnaNumDTO appEmpAnaNumDTO = new AppEmpAnaNumDTO();
            appEmpAnaNumDTO.setWorkRoleId(workRoleId);
            appEmpAnaNumDTO.setName(workTypeName);
            appEmpAnaNumDTO.setLocaleNum(localeNum);
            appEmpAnaNumDTO.setOffLocaleNum(offLocaleNum);
            appEmpAnaNumDTO.setAbsenceNum(absenceNum);
            attendStateEmpList.add(appEmpAnaNumDTO);
        }

        workTypeEmpList.sort((x, y) -> y.getId() - x.getId());
        appBoardEmpNumDTO.setWorkTypeEmpList(workTypeEmpList);
        appBoardEmpNumDTO.setAttendStateEmpList(attendStateEmpList);
        data.setAppBoardEmpNumDTO(appBoardEmpNumDTO);

        // 过去7天的人员进出场统计
        Date now = new Date();
        Date today = DateUtil.getDateBegin(now);
        Date startDate = DateUtil.addDays(today, -6);
        List<AppEmpAnaWeekDataDTO> enterStatList = appEmpEnterRecordMapper.selectDayStatStat(deptId, startDate, today);
        Map<Date, AppEmpAnaWeekDataDTO> enterStatMap = CollectionUtil.list2Map(enterStatList, AppEmpAnaWeekDataDTO::getDate);
        List<Date> dateList = DateUtil.getDateListBetween(startDate, today);
        List<AppEmpAnaWeekDataDTO> weekDataList = new ArrayList<>(dateList.size());
        for (Date date : dateList) {
            AppEmpAnaWeekDataDTO record = enterStatMap.containsKey(date) ? enterStatMap.get(date) : new AppEmpAnaWeekDataDTO(date, 0, 0);
            weekDataList.add(record);
        }

        // 人员打卡记录
        AttendType attendType = commonEmpConfigManager.getAttendType(deptId);
        Date endTime = DateUtil.getDateEnd(today);
        List<BoardEmpAttendRecordDTO> appEmpAttendRecordList = appEmpAttendRecordMapper.selectByDeptIdAndTime(deptId, attendType.getValue(), today, endTime);
        data.setAttendRecordList(appEmpAttendRecordList);


        // 查找人员报警数量
//        Integer dropWarnCnt = appEmpWarnMapper.countWarnNum(Collections.singletonList(deptId), AppEmpWarnRuleType.DROP.value(), DateUtil.addDays(now, -1), now);
//        Integer sosWarnCnt = appEmpWarnMapper.countWarnNum(Collections.singletonList(deptId), AppEmpWarnRuleType.SOS.value(), DateUtil.addDays(now, -1), now);
//        Integer doffWarnCnt = appEmpWarnMapper.countWarnNum(Collections.singletonList(deptId), AppEmpWarnRuleType.DOFF.value(), DateUtil.addDays(now, -1), now);
//        Integer fallWarnCnt = appEmpWarnMapper.countWarnNum(Collections.singletonList(deptId), AppEmpWarnRuleType.FALL.value(), DateUtil.addDays(now, -1), now);
//        List<KeyAndSizeDTO> keyAndSizeDTO = appEmpWarnMapper.countWarnByType(Collections.singletonList(deptId), DateUtil.addDays(now, -1), now);
//        keyAndSizeDTO.forEach(keyAndSizeDTO1 -> {
//            if((AppEmpWarnRuleType.DROP.value()+"").equals(keyAndSizeDTO1.getKeyString())){
//                data.setDropWarnCnt(keyAndSizeDTO1.getSizeNum());
//            }else if((AppEmpWarnRuleType.SOS.value()+"").equals(keyAndSizeDTO1.getKeyString())){
//                data.setSosWarnCnt(keyAndSizeDTO1.getSizeNum());
//            }else if((AppEmpWarnRuleType.DOFF.value()+"").equals(keyAndSizeDTO1.getKeyString())){
//                data.setDoffWarnCnt(keyAndSizeDTO1.getSizeNum());
//            }else if((AppEmpWarnRuleType.FALL.value()+"").equals(keyAndSizeDTO1.getKeyString())){
//                data.setFallWarnCnt(keyAndSizeDTO1.getSizeNum());
//            }
//        });

        data.setWeekDataList(weekDataList);
//        data.setDoffWarnCnt(doffWarnCnt);
//        data.setDropWarnCnt(dropWarnCnt);
//        data.setSosWarnCnt(sosWarnCnt);
//        data.setFallWarnCnt(fallWarnCnt);

        return data;
    }

    @Override
    public AppEmpNumDTO getEmpNum(List<Integer> deptIds) throws BizException {
        logger.info("大屏-在岗人数,deptIds:{}", deptIds);
        Integer empNum = appEmpMapper.selectPostEmpNum(deptIds);
        Integer empAttendNum = appEmpDataMapper.countAttendNum(deptIds);

        AppEmpNumDTO data = new AppEmpNumDTO();
        data.setEmpAttendNum(empAttendNum);
        data.setEmpNum(empNum);
        return data;
    }

    @Override
    public List<GisEmpDTO> getGisEmpData(Integer deptId) throws BizException {
        logger.info("获取人员数据,deptId:{}", deptId);
        return appEmpMapper.selectGisEmpData(deptId);
    }

    @Override
    public List<EmpDataDTO> getAttendData(Integer deptId, Date startDate, Date endDate) throws BizException {
        logger.info("获取每天的出勤数据统计,deptId:{}", deptId);
        List<EmpDataDTO> empDataList = appEmpDayMapper.selectEmpNumTotalPerDay(deptId, startDate, endDate);
        empDataList.sort(Comparator.comparing(EmpDataDTO::getDate));
        for (EmpDataDTO empData : empDataList) {
            Integer empTotal = empData.getEmpTotal();
            // 获取计划出勤
            EmpAttendPlan empAttendPlan = appEmpDeptDayMapper.selectByDeptIdAndDate(deptId, empData.getDate());
            if (empAttendPlan != null) {
                empTotal = empAttendPlan.getPlanAttendNum();
            }
            Integer attendNum = empData.getAttendNum();
            Double rate = empTotal > 0 ? MathUtil.divide(attendNum, empTotal, 2) : 0;
            empData.setRate(rate);
        }
        return empDataList;
    }

    @Override
    public List<AppBoardEmpGroupCountDTO> countGroupData(Integer deptId) throws BizException {
        return appEmpGroupMapper.countByCorp(deptId);
    }


    @Override
    public AppBoardEmpAnalysisDTO empAnalysis(Integer deptId, Date startDate, Date endDate) throws BizException {

        if (endDate != null) {
            endDate = DateUtil.getDateEnd(endDate);
        }
        Integer empNum = appEmpMapper.selectPostEmpNum(Collections.singletonList(deptId));
        Integer empAttendNum = appEmpDataMapper.countAttendNum(Collections.singletonList(deptId));
        AppBoardEmpAnalysisDTO data = new AppBoardEmpAnalysisDTO();
        data.setTotal(empNum);
        if (empAttendNum == null || empAttendNum == 0) {
            data.setAttendRate(0D);
        } else {
            data.setAttendRate(MathUtil.round(MathUtil.divide(empAttendNum, empNum, 4) * 100, 2));
        }
        //进出场统计
        AppEmpAnaWeekDataDTO stat = appEmpEnterRecordMapper.selectTotalStat(deptId, startDate, endDate);
        data.setEmpEnterNum(stat.getEnterNum());
        data.setEmpOuterNum(stat.getOuterNum());
        return data;
    }

    @Override
    public AppEmpBoardRecordAnalysisDTO empRecordAnalysis(Integer deptId, Date startDate, Date endDate) throws BizException {
        if (endDate != null) {
            endDate = DateUtil.getDateEnd(endDate);
        }
        AppEmpBoardRecordAnalysisDTO data = appFaceGateRecordMapper.selectRecordAnalysis(deptId, startDate, endDate);
        if (data == null) {
            data = new AppEmpBoardRecordAnalysisDTO();
            data.setInNum(0);
            data.setOutNum(0);
        }
        List<AppFaceGateRecordDTO> records = new ArrayList<>();
        AppFaceGateRecordDTO in = appFaceGateRecordMapper.selectLatestRecord(deptId, Direction.IN.getValue(), startDate, endDate);
        if (in != null) {
            records.add(in);
        }
        AppFaceGateRecordDTO out = appFaceGateRecordMapper.selectLatestRecord(deptId, Direction.OUT.getValue(), startDate, endDate);
        if (out != null) {
            records.add(out);
        }
        data.setRecords(records);
        return data;
    }

    @Override
    public AppEmpBoardRecordAnalysisDTO empRecordAnalysis2(Integer deptId, Date startDate, Date endDate) throws BizException {
        if (endDate != null) {
            endDate = DateUtil.getDateEnd(endDate);
        }
        List<AppFaceGateRecordDTO> inList = appFaceGateRecordMapper.selectRecordList(deptId, Direction.IN.getValue(), startDate, endDate);
        List<AppFaceGateRecordDTO> outList = appFaceGateRecordMapper.selectRecordList(deptId, Direction.OUT.getValue(), startDate, endDate);
        Map<Integer, List<AppFaceGateRecordDTO>> inMap = CollectionUtil.groupBy(inList, AppFaceGateRecordDTO::getEmpId);
        Map<Integer, List<AppFaceGateRecordDTO>> outMap = CollectionUtil.groupBy(outList, AppFaceGateRecordDTO::getEmpId);
        Set<Integer> empIdList = new TreeSet<>();
        empIdList.addAll(inMap.keySet());
        empIdList.addAll(outMap.keySet());
        logger.info("人员ID集合:{}", empIdList);
        List<AppFaceGateRecordDTO> records = new ArrayList<>(empIdList.size());
        for (Integer empId : empIdList) {
            AppFaceGateRecordDTO recordDTO = null;
            if (inMap.containsKey(empId)) {
                List<AppFaceGateRecordDTO> inRecordList = inMap.get(empId);
                recordDTO = recordDTO == null ? inRecordList.get(0) : recordDTO;
                recordDTO.setInTime(inRecordList.get(0).getShowTime());
                recordDTO.setInImgUrl(inRecordList.get(0).getPhotoUrl());
                recordDTO.setDirection(null);
                recordDTO.setShowTime(recordDTO.getInTime());
                recordDTO.setPhotoUrl(null);
            }
            if (outMap.containsKey(empId)) {
                List<AppFaceGateRecordDTO> outRecordList = outMap.get(empId);
                recordDTO = recordDTO == null ? outRecordList.get(0) : recordDTO;
                recordDTO.setOutTime(outRecordList.get(0).getShowTime());
                recordDTO.setOutImgUrl(outRecordList.get(0).getPhotoUrl());
                recordDTO.setDirection(null);
                recordDTO.setShowTime(recordDTO.getOutTime());
                recordDTO.setPhotoUrl(null);
            }
            records.add(recordDTO);
        }
        AppEmpBoardRecordAnalysisDTO data = new AppEmpBoardRecordAnalysisDTO();
        data.setInNum(inList.size());
        data.setOutNum(outList.size());
        data.setRecords(records.stream().sorted(Comparator.comparing(AppFaceGateRecordDTO::getShowTime).reversed()).limit(20).collect(Collectors.toList()));
        return data;
    }
}
